package com.tyylab.kestrel.framework.spring.rpc.feign.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.tyylab.kestrel.framework.core.annoutil.SpringMVCAnnotationUtil;
import com.tyylab.kestrel.framework.core.build.DefaultInterfaceBuilder;
import com.tyylab.kestrel.framework.core.build.IInterfaceBuilder;
import com.tyylab.kestrel.framework.core.build.ProxyMethodNameGenerator;
import com.tyylab.kestrel.framework.spring.rpc.feign.annoutil.SpringFeignAnnotationUtil;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.description.annotation.AnnotationDescription;
import org.springframework.http.MediaType;

import java.lang.reflect.Method;

import static com.tyylab.kestrel.framework.spring.rpc.feign.util.ConstValue.FeignClientSubFix;

/**
 * Generate Feign API for Native Java API
 * @author tyylab
 */
@Slf4j
@RequiredArgsConstructor
public class FeignApiGenerator {
    @NonNull
    FeignClientConfigGenerator configGenerator;
    
    private FeignFallbackGenerator fallbackGenerator = new FeignFallbackGenerator();
    
    public Class<?> generateFeignApi(Class<?> api,Class<?> fallbackClass) {
        //Class name
        String className = api.getName() + FeignClientSubFix;
        // get config

        //
        IInterfaceBuilder interfaceBuilder = new DefaultInterfaceBuilder();

        AnnotationDescription intfAnno = generateFeignClientAnnotation(api, fallbackClass);
        interfaceBuilder =
            interfaceBuilder.defineInft()
                    .intf(className)
                    .annotate(intfAnno)
                    .end();

        Method[] methods = api.getDeclaredMethods();
        //define methods
        for (Method method : methods) {
            String methodName = ProxyMethodNameGenerator.generateMethodName(method);
            AnnotationDescription annotationDescription = generatePostMappingAnnotation(method);
            interfaceBuilder = interfaceBuilder.declareMethod()
                    .method(methodName, method.getGenericReturnType())
                    .param("arg0", JSONObject.class)
                    .annotateMethod(annotationDescription)
                    .annotateParams(0, SpringMVCAnnotationUtil.requestBody(true))
                    .end();
        }
        return interfaceBuilder.build();
    }

    // generate class feign annotation
    public AnnotationDescription generateFeignClientAnnotation(Class<?> api, Class<?> fallbackClass) {
        String serviceName = configGenerator.getFeignClientName(api);
        String path = configGenerator.getFeignClientPath(api);
        String contextId = StrUtil.lowerFirst(api.getSimpleName());
        
        // // Generate fallback class
        // Class<?> fallbackClass = fallbackGenerator.generateFallback(api);
        
        AnnotationDescription annotationDescription = SpringFeignAnnotationUtil.feignClient(
                serviceName, contextId,
//                "nacos://"+"85d9804f-f799-459d-a1f7-e7395872c629/"+serviceName,
                "",
                path, false, false, fallbackClass, null,
                new String[]{}, new Class<?>[]{});
        return annotationDescription;
    }

    public AnnotationDescription generatePostMappingAnnotation(Method method) {
        String path = ProxyMethodNameGenerator.generateMethodName(method);
        AnnotationDescription annotationDescription = SpringMVCAnnotationUtil.postMapping(null,new String[]{path},
                new String[]{}, new String[]{}, null,new String[]{MediaType.APPLICATION_JSON.toString()});
        return annotationDescription;
    }

//    public static void main(String[] args) {
//        FeignApiGenerator generator = new FeignApiGenerator(new FeignClientConfigGenerator());
//        Class clz = generator.generateFeignApi(ITest.class);
//        System.out.println(clz.getName());
//
//        System.out.println(MediaType.APPLICATION_JSON_VALUE.toString());
//    }
}
